package com.aididi.concurrent;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicStampedReference;

/**
 * @Auther: zx.xu
 * @Description:    如何解决AtomicInteger的ABA的问题       使用AtomicStampedReference
 */
public class AtomicIntegerDemo {
    private static AtomicInteger nextHashCode =
            new AtomicInteger();
    private static final int HASH_INCREMENT = 0x61c88647;

    private static AtomicInteger atomicInteger = new AtomicInteger(100);

    private static AtomicStampedReference<Integer> atomicStampedRef =
            new AtomicStampedReference<Integer>(100, 0);


    public static void main(String[] args) throws InterruptedException{
        //获取当前的值，并加上预期的值
        int threadLocalHashCode = nextHashCode.getAndAdd(HASH_INCREMENT);
        System.out.println(threadLocalHashCode);
        //thread1线程去修改atomicInteger的值
        Thread thread1 = new Thread(() -> {
            atomicInteger.compareAndSet(100, 110);
            atomicInteger.compareAndSet(110, 100);
        });

        //thread2线程去读取内存值并设置新值
        Thread thread2 = new Thread(() -> {
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("thread2--AtomicInteger compareAndSet : " + atomicInteger.compareAndSet(100, 110));
            System.out.println("thread2--AtomicInteger value : " + atomicInteger.get());

        });

        thread1.start();
        thread2.start();
        thread1.join();
        thread2.join();

        Thread refT1 = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    TimeUnit.SECONDS.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                atomicStampedRef.compareAndSet(100, 101,
                        atomicStampedRef.getStamp(), atomicStampedRef.getStamp()+1);
                atomicStampedRef.compareAndSet(101, 100,
                        atomicStampedRef.getStamp(), atomicStampedRef.getStamp()+1);
            }
        });

        Thread refT2 = new Thread(new Runnable() {
            @Override
            public void run() {
                int stamp = atomicStampedRef.getStamp();
                System.out.println("before sleep : stamp = " + stamp);    // stamp = 0
                try {
                    TimeUnit.SECONDS.sleep(2);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("after sleep : stamp = " + atomicStampedRef.getStamp());//stamp = 2
                boolean c3 = atomicStampedRef.compareAndSet(100, 101, stamp, stamp+1);
                System.out.println(c3);        //false
                System.out.println(Thread.currentThread().getName() + "  最新版本号：" + atomicStampedRef.getStamp() + "，是否修改成功：" + c3 + "，当前值是：" + atomicStampedRef.getReference());
            }
        });

        refT1.start();
        refT2.start();
        System.out.println("thread 2  end : stamp = " + atomicStampedRef.getStamp());    // stamp = 0

    }

}
